﻿using System;
using System.Collections.Generic;
using System.Linq;
using AcademicPlanner.Data;
using AcademicPlanner.Data.Entities;
using AcademicPlanner.Data.Repositories;

namespace AcademicPlanner.Domain.Models
{
	/// <summary>
	/// Account represents an account in the application. An <c>Account</c>
	/// allows access to the application's functionalities through its <c>User</c>.
	/// </summary>
	/// <seealso cref="T:User"/>
	/// <version>1.0</version>
	/// <since>1.0</since>
    public class Account : Model
    {
		/// <summary>
		/// The <c>User</c> for this Account.
		/// </summary>
		/// <version>1.0</version>
		/// <since>1.0</since>
		protected User user;


		/// <summary>
		/// Gets the data layer repository for this Account's underlying data representation.
		/// </summary>
		/// <version>1.0</version>
		/// <since>1.0</since>
		/// <version>1.0</version>
		/// <since>1.0</since>
		protected override EntityRepository EntityRepo { get { return AccountEntityRepository.GetInstance(); } }

		/// <summary>
		/// Gets this Account's underlying data representation.
		/// </summary>
		/// <version>1.0</version>
		/// <since>1.0</since>
		/// <version>1.0</version>
		/// <since>1.0</since>
		protected AccountEntity Entity { get { return (AccountEntity)entity; } }

		/// <summary>
		/// Gets whether this Account is activated or not.
		/// </summary>
		/// <version>1.0</version>
		/// <since>1.0</since>
		public bool IsActivated { get { return Entity.Activated; } }

		/// <summary>
		/// Gets when this Account was activated.
		/// </summary>
		/// <version>1.0</version>
		/// <since>1.0</since>
		public DateTime ActivationDate { get { return (DateTime) Entity.Date_Activated; } }

		/// <summary>
		/// Gets when this Account was inactivated.
		/// </summary>
		/// <version>1.0</version>
		/// <since>1.0</since>
		public DateTime InActivationDate { get { return (DateTime)Entity.Date_Inactivated; } }

		/// <summary>
		/// Gets the <c>User</c> for this Account.
		/// </summary>
		/// <version>1.0</version>
		/// <since>1.0</since>
		public User User { get { return user; } }


		/// <summary>
		/// No argument constructor; invokes the matching base class constructor.
		/// </summary>
		/// <seealso cref="M:AcademicPlanner.Domain.Model.Model"/>
		/// <version>1.0</version>
		/// <since>1.0</since>
		public Account()
			: base()
		{

		}

		/// <summary>
		/// Initializes a Account with the given <c>AccountEntity</c> by invoking the matching base class constructor.
		/// </summary>
		/// <seealso cref="M:AcademicPlanner.Domain.Model.Model(Entity)"/>
		/// <version>1.0</version>
		/// <since>1.0</since>
		public Account(AccountEntity pEntity)
			: base(pEntity)
		{
			
		}


		/// <summary>
		/// Persists this Account's data to the data storage. This method first
		/// persists this Account's <c>User</c> before persisting this Account.
		/// </summary>
		/// <seealso cref="M:AcademicPlanner.Domain.Model.Persit"/>
		/// <version>1.0</version>
		/// <since>1.0</since>
		public override void Persit()
		{
			user.Persit();
			base.Persit();
		}

		/// <summary>
		/// Customizes the initialization of this Account. This method is invoked by
		/// <see cref="M:AcademicPlanner.Domain.Model.Init"/> and initializes this
		/// Account's <c>User</c> using this Account's underlying <c>AccountEntity</c>'s
		/// <c>UserEntity</c>.
		/// </summary>
		/// <seealso cref="M:AcademicPlanner.Domain.Model.Init"/>
		/// <version>1.0</version>
		/// <since>1.0</since>
		protected override void PostInit()
		{
			base.PostInit();
			user = DomainMaster.ModelsFountain.GetUser(Entity.UserEntity);
		}

		/// <summary>
		/// Sets this Account's properties as well as its <c>User</c>'s.
		/// </summary>
		/// <param name="pActivated">The flag to activate or deactivate this Account.</param>
		/// <param name="pUserName">The <c>User</c>'s username.</param>
		/// <param name="pUserPassword">The <c>User</c>'s password.</param>
		/// <exception cref="T:InvalidModelPropertiesException">
		/// Thrown with an error code of <c>DomainErrorCode.M_INVALID_ACCOUNT_USER_PROPERTIES</c>
		/// if validation errors occured while updating the <c>User</c>'s properties; the validation
		/// errors for the <c>User</c> are available as <c>InnerErrors</c> indexed by "User".
		/// </exception>
		/// <seealso cref="User.Set"/>
		/// <version>1.0</version>
		/// <since>1.0</since>
		public void Set(bool ? pActivated, string pUserName, string pUserPassword)
		{
			if (pActivated != null)
			{
				Entity.Activated = (bool)pActivated;
				Entity.UserEntity.Active = (bool)pActivated;
				if ((bool)pActivated)
					Entity.Date_Activated = DateTime.Now;
				else
					Entity.Date_Inactivated = DateTime.Now;
			}

			try
			{
				user.Set(pUserName, pUserPassword);
			}
			catch (InvalidModelPropertiesException vIx)
			{
				var vErrs = new InvalidModelPropertiesErrorCollection("Account");
				vErrs.AddInner("User", vIx.Errors);
				throw new InvalidModelPropertiesException(DomainErrorCode.M_INVALID_ACCOUNT_USER_PROPERTIES,
															vErrs);
			}
		}
    }
}
